/*
 * Copyright (C) 2012 Santiago Valdarrama
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package com.yuanmei.stockeyes.data;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Executors;

import financedata.historicalquotes.Interval;
import android.app.SearchManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.provider.BaseColumns;
import android.util.Log;
import android.os.AsyncTask;

import com.yuanmei.stockeyes.MarketCollectorService;
import com.yuanmei.stockeyes.artifacts.Constants;
import com.yuanmei.stockeyes.artifacts.Extensions;
import com.yuanmei.stockeyes.data.HistoryQuotesDataBase.HistoryRecord;
import com.yuanmei.stockeyes.model.Stock;
import com.yuanmei.stockeyes.model.StockAnalysis;
import com.yuanmei.stockeyes.model.Stock.TimeSeqData;
import com.yuanmei.stockeyes.receivers.ConnectivityBroadcastReceiver;

public class DataProvider {

    private final static String TAG = "DataProvider";

    private static LonghornDatabase      longhornDatabase  = null;
    private static HistoryQuotesDataBase hisQuotesDatabase = null;
    private static StockInfoDatabase     stockInfoDatabase = null;
    private static List<Stock> stocks;
    private static HashMap<String, WeakReference<StockQuoteCollectorObserver>> observers;

    public final static String HIS_DAY   = "his_day";
    public final static String HIS_WEEK  = "his_week";
    public final static String HIS_MONTH = "his_month";

    static {
        DataProvider.stocks = null;
        DataProvider.observers = new HashMap<String, WeakReference<StockQuoteCollectorObserver>>();
    }
    
    public static void initialize(Context context) {
        if (DataProvider.longhornDatabase == null) {
            DataProvider.longhornDatabase = new LonghornDatabase(context);
        }

        if (DataProvider.hisQuotesDatabase == null) {
            DataProvider.hisQuotesDatabase = new HistoryQuotesDataBase(context);
        }
        
        if (DataProvider.stockInfoDatabase == null) {
            DataProvider.stockInfoDatabase = new StockInfoDatabase(context);
        }
    }

    public static void registerObserver(StockQuoteCollectorObserver observer) {
        DataProvider.observers.put(observer.getClass().getName(),
                new WeakReference<DataProvider.StockQuoteCollectorObserver>(
                        observer));
    }

    public static void startStockQuoteCollectorService(Context context,
            String ticker) {
        Intent intent = new Intent(context, MarketCollectorService.class);
        if (ticker != null) {
            intent.putExtra(MarketCollectorService.EXTRA_TICKER, ticker);
        }
        context.startService(intent); 

        if (null == ticker) {
            startUpdateHistoryData(context, null, null);
        } else {
            startUpdateHistoryData(context, ticker, null);
        }
    }

    private static boolean sCheckAndUpdateStockInfoTaskIsRunning = false;
    public static boolean isNeedCheckStockInfoUpdate(Context context) {

        Log.d("DEBUG", "KMS isNeedCheckStockInfoUpdate 000");
        if  (sCheckAndUpdateStockInfoTaskIsRunning) {
            return false;
        }

        long last_check = context.getSharedPreferences(Constants.PREFERENCES,
                Context.MODE_PRIVATE).getLong(Constants.PREFERENCE_STOCKINFO_LAST_CHECK, 0);

        Calendar check_date = Calendar.getInstance();
        check_date.setTimeInMillis(last_check);

        Calendar curr_date = Calendar.getInstance();
        curr_date.setTimeInMillis(System.currentTimeMillis());

        if (check_date.get(Calendar.YEAR) < curr_date.get(Calendar.YEAR)) {
            return true;
        } else if ((check_date.get(Calendar.YEAR) == check_date.get(Calendar.YEAR))
                && (check_date.get(Calendar.DAY_OF_YEAR) < (curr_date.get(Calendar.DAY_OF_YEAR)))) {
            return true;
        }

        return false;
    }

    public static void startCheckAndUpdateStockInfo(Context context) {
        if ( !(Extensions.areWeOnline(context))
                || !Extensions.areWeUsingWiFi(context))
            return;

        sCheckAndUpdateStockInfoTaskIsRunning = true;

        new AsyncTask<Context, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Context... params) {
                Context in_context = params[0];
                try {
                    getStockInfoDatabase(in_context).checkAndUpdateStockInfo(in_context);

                    SharedPreferences sharedPreferences = in_context
                            .getSharedPreferences(Constants.PREFERENCES,
                                    Context.MODE_PRIVATE);
                    sharedPreferences.edit().
                            putLong(Constants.PREFERENCE_STOCKINFO_LAST_CHECK,System.currentTimeMillis())
                            .apply();

                    Log.i(TAG, "UPDATE StockInfo DataBase complete");
                } catch (Exception e) {
                    Log.w(TAG, "UPDATE StockInfo DataBase failed exception=" + e);
                    e.printStackTrace();
                }
                return true;
            }

            @Override
            protected void onPostExecute(Boolean isUpdateComplete) {
                sCheckAndUpdateStockInfoTaskIsRunning = false;
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, context);
    }

    public static boolean isHistoricalQuotesNeedUpdate(final Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                Constants.PREFERENCES, Context.MODE_PRIVATE);
        long lastUpdate = sharedPreferences.getLong(
                Constants.PREFERENCE_HISDB_LAST_UPDATE, 0);
        Calendar update_date = Calendar.getInstance();
        update_date.setTimeInMillis(lastUpdate);

        Calendar curr_date = Calendar.getInstance();
        long current_time_ms = System.currentTimeMillis();
        curr_date.setTimeInMillis(current_time_ms);


        if (update_date.get(Calendar.YEAR) < curr_date.get(Calendar.YEAR)) {
            return true;
        } else if ((update_date.get(Calendar.YEAR) == curr_date.get(Calendar.YEAR))
                && (update_date.get(Calendar.DAY_OF_YEAR)
                < (curr_date.get(Calendar.DAY_OF_YEAR)))) {
            return true;
        }

        return false;
    }

    public interface AsyncDownloadCallback {
        public void onDownloadOver();
    }

    private static final Object sAsyncHistoryUpdateLock = new Object();

//    private static List<AsyncDownloadCallback> sAsyncHisdataCallbackList = new ArrayList<AsyncDownloadCallback>();

//    private class AsyncUpdateParams{
//        private Context    mContext;
//        private String     mTicker;
//        private AsyncDownloadCallback    mCallback;
//
//
//        private AsyncUpdateParams(Context context, String tickers, // Interval[] intervals,
//                           AsyncDownloadCallback callback) {
//            mContext   = context;
//            mTicker    = tickers;
//            mCallback  = callback;
//        }
//    };

    private static void startAsyncTaskForUpdateHistoryQuotes(final Context context,
                                                 final String symbol_code,
                                                 final AsyncDownloadCallback callback) {
        new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... params) {
                Boolean isDownloadSuccess = false;
                int retry_cnt = 3;
                try {
                    do {
                        if (true == updateStockHisData(context, symbol_code)) {
                            isDownloadSuccess = true;
                            Log.i(TAG, String.format("Async update stock(%s)'s hisqoutes success",
                                    symbol_code));
                            break;
                        } else {
                            Log.i(TAG, String.format("Async update stock(%s)'s hisqoutes Fail, retry times=%d ",
                                    symbol_code, retry_cnt));
                            retry_cnt--;
                        }
                    } while (retry_cnt > 0);
                } catch (Exception e) {
                    isDownloadSuccess = false;
                    Log.w(TAG, "Async update stock("+ symbol_code +")'s hisqoutes  exception=" + e);
                }
                return isDownloadSuccess;
            }

            @Override
            protected void onPostExecute(Boolean isDownloadSuccess) {
                if (callback != null) {
                    callback.onDownloadOver();
                }
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }

    public static void startUpdateHistoryData(Context context,
                                              String ticker,
                                              AsyncDownloadCallback callback) {
        if (!(Extensions.areWeOnline(context))
                || !Extensions.areWeUsingWiFi(context))
            return;

        synchronized (sAsyncHistoryUpdateLock) {
            if (null == ticker) {
//                SharedPreferences sharedPreferences = context.getSharedPreferences(Constants.PREFERENCES,
//                        Context.MODE_PRIVATE);
//                Calendar update_date = Calendar.getInstance();
//                update_date.setTimeInMillis(sharedPreferences.getLong(Constants.PREFERENCE_HISDB_LAST_UPDATE, 0));
//
//                Calendar curr_date = Calendar.getInstance();
//                curr_date.setTimeInMillis(System.currentTimeMillis());

//                if (update_date.get(Calendar.YEAR) > curr_date.get(Calendar.YEAR)) {
//                    return;
//                } else if ((update_date.get(Calendar.YEAR) == curr_date.get(Calendar.YEAR))
//                        && (update_date.get(Calendar.DAY_OF_YEAR) >= (curr_date.get(Calendar.DAY_OF_YEAR)))) {
//                    return;
//                }

                String[] tickers = getStockDataTickers(context);
                for (String symbol : tickers) {
                    startAsyncTaskForUpdateHistoryQuotes(context, symbol, callback);
                }

//                SharedPreferences.Editor editor =sharedPreferences.edit();
//                editor.putLong(Constants.PREFERENCE_HISDB_LAST_UPDATE, System.currentTimeMillis());
//                editor.commit();
            } else {
                startAsyncTaskForUpdateHistoryQuotes(context, ticker, callback);
            }
        }
    }

    public static Cursor search(Context context, String query) {
        query = query.toLowerCase();

        String[] columns = new String[] { BaseColumns._ID,
                SearchManager.SUGGEST_COLUMN_TEXT_1,
                //SearchManager.SUGGEST_COLUMN_TEXT_2,
                SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID };

        return getStockInfoDatabase(context).search(query, columns);
    }

    public static List<Stock> getWatchList(Context context) {
        if (DataProvider.stocks == null) {
            DataProvider.stocks = new ArrayList<Stock>();

            Cursor cursor = DataProvider.getLonghornDatabase(context)
                    .getWatchList();
            for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
                    .moveToNext()) {
                Stock stock = new Stock(
                        cursor.getString(cursor
                                .getColumnIndex(LonghornDatabase.KEY_STOCK_CODE)),
                        cursor.getString(cursor
                                .getColumnIndex(LonghornDatabase.KEY_STOCK_NAME)),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_CHANGE_PERCENTAGE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_CHANGE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_PRICE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_OPEN),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_LOW),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_HIGH),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_YESTCLOSE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_VOLUME),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_TURNOVER),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL5),
                        cursor.getString(cursor
                                .getColumnIndex(LonghornDatabase.KEY_STOCK_UPDATE)));

                String symbol_code = stock.getCode();
                Cursor stockInfoCursor = getStockInfoDatabase(context).getStockSearch(symbol_code); 
                if (stockInfoCursor.getCount() > 0) {
                    stockInfoCursor.moveToFirst();
                    int market_id = stockInfoCursor.getInt(stockInfoCursor
                            .getColumnIndex(StockInfoDatabase.KEY_STOCK_SEARCH_MARKET));
                    String m_code = stockInfoCursor.getString(stockInfoCursor
                            .getColumnIndex(StockInfoDatabase.KEY_STOCK_SEARCH_M_CODE));
                    stock.setMarketId(market_id);
                    stock.setMarketCode(m_code);
                    
                } 
                stockInfoCursor.close();
                
                DataProvider.stocks.add(stock);
            }

            cursor.close();
        }

        return DataProvider.stocks;
    }

    public static boolean addStockToWatchList(Context context, String symbol) {
        if (getStock(context, symbol) == null) {
            Cursor cursor = getStockInfoDatabase(context).getStockSearch(symbol);
            cursor.moveToFirst();

            String name = cursor.getString(cursor
                    .getColumnIndex(StockInfoDatabase.KEY_STOCK_SEARCH_NAME));
            int market_id = cursor.getInt(cursor
                    .getColumnIndex(StockInfoDatabase.KEY_STOCK_SEARCH_MARKET));
            String m_code = cursor.getString(cursor
                    .getColumnIndex(StockInfoDatabase.KEY_STOCK_SEARCH_M_CODE));

            
            cursor.close();

            Stock stock = new Stock(symbol, name, market_id, m_code);
            
            getHisQutoesDatabase(context).createHisQuotesTable(symbol);

            if (getLonghornDatabase(context).addStockToWatchList(symbol, name)) {
                getWatchList(context).add(stock);

                if (Extensions.areWeOnline(context)) {
                    startStockQuoteCollectorService(context, stock.getCode());
                    return true;
                } else {
                    Log.d(TAG,
                            "There's no Internet connection to collect the market information for "
                                    + symbol
                                    + ". Let's start listening for connectivity updates.");

                    SharedPreferences sharedPreferences = context
                            .getSharedPreferences(Constants.PREFERENCES,
                                    Context.MODE_PRIVATE);
                    Editor editor = sharedPreferences.edit();
                    editor.putBoolean(
                            Constants.PREFERENCE_STATUS_WAITING_FOR_CONNECTIVITY,
                            true);
                    editor.commit();

                    ComponentName componentName = new ComponentName(context,
                            ConnectivityBroadcastReceiver.class);
                    context.getPackageManager().setComponentEnabledSetting(
                            componentName,
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                            PackageManager.DONT_KILL_APP);
                }

                return false;
            }
        }

        return true;
    }

    public static void reorderStocks(Context context, Stock stock1, Stock stock2) {
        int stock1Position = DataProvider.stocks.indexOf(stock1);
        int stock2Position = DataProvider.stocks.indexOf(stock2);

        DataProvider.stocks.remove(stock1Position);
        DataProvider.stocks.add(stock1Position, stock2);

        DataProvider.stocks.remove(stock2Position);
        DataProvider.stocks.add(stock2Position, stock1);

        getLonghornDatabase(context).reorderStocks(stock1, stock2);
    }

    public static void removeStocksFromWatchList(Context context,
            List<Stock> list) {
        for (Stock stock : list) {
            DataProvider.getWatchList(context).remove(stock);
            getHisQutoesDatabase(context).deleteHisQuotesTable(
                    stock.getCode());
            getLonghornDatabase(context).removeStockFromWatchList(
                    stock.getCode());
        }
    }

    public static Stock getStock(Context context, String symbol) {
        for (Stock stock : getWatchList(context)) {
            if (stock.getCode().equals(symbol)) {
                return stock;
            }
        }
        return null;
    }

    public static String[] getStockDataTickers(Context context) {
        Cursor cursor = getLonghornDatabase(context).getStockDataTickers();

        String[] tickers = new String[cursor.getCount()];
        int index = 0;
        for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
            String code = cursor.getString(cursor
                    .getColumnIndex(LonghornDatabase.KEY_STOCK_CODE));
            tickers[index] = code;
            index++;
        }

        cursor.close();

        return tickers;
    }

    public static void updateStockData(Context context, String code,
            Float changePercentage, Float change, Float price, Float open,
            Float Low, Float High, Float yestClose, Float volume,
            Float turnover, Float bid5, Float bidvol5, Float bid4,
            Float bidvol4, Float bid3, Float bidvol3, Float bid2,
            Float bidvol2, Float bid1, Float bidvol1, Float ask1,
            Float askvol1, Float ask2, Float askvol2, Float ask3,
            Float askvol3, Float ask4, Float askvol4, Float ask5,
            Float askvol5, String update) {
        getLonghornDatabase(context).updateStockData(code, changePercentage,
                change, price, open, Low, High, yestClose, volume, turnover,
                bid5, bidvol5, bid4, bidvol4, bid3, bidvol3, bid2, bidvol2,
                bid1, bidvol1, ask1, askvol1, ask2, askvol2, ask3, askvol3,
                ask4, askvol4, ask5, askvol5, update);
    }

    public static void updateTimeData(Context context, String code, long time,
            Float price, Float vol, Float turnover) {
        getLonghornDatabase(context).updateStockTimeData(code, time, price,
                vol, turnover);
    }

    private static boolean updateStockHisData(Context context, String symbol_code) {
        Stock stock = getStock(context, symbol_code);
        if (null == stock) {
            Log.e(TAG, "The Input symbol=" + symbol_code + " not match a stock");
            return false;
        }

        return getHisQutoesDatabase(context).updateTabData(symbol_code,
                stock.getMarketCode(), stock.getMarketId());
    }

    public static List<HistoryRecord> getLastNumHisRecords(Context context,
                                                           String symbol_code,
                                                           Interval interval,
                                                           int lastNum, 
                                                           boolean isReValid,
                                                           AsyncDownloadCallback callback) {
        Log.d(TAG, "GetLastNumHisRecords interval=" + interval.getTag());
        List<HistoryRecord> his_recs = getHisQutoesDatabase(context).
                getLastNumRecords(symbol_code, interval, lastNum);
        if ((null == his_recs) && isReValid) {
            DataProvider.startUpdateHistoryData(context, symbol_code, callback);
        }
        return his_recs;
    }

    /*
    private static boolean updateAllStockHisData(Context context, String[] tickers) {
         
        boolean isSucc = true;
        for (int i = 0; i < tickers.length; i++) {
            String symbol_code = tickers[i];
            if (false == updateStockHisData(context, symbol_code, Interval.DAILY) )
                return false;
            if (false == updateStockHisData(context, symbol_code, Interval.WEEKLY) )
                return false;
            if (false == updateStockHisData(context, symbol_code, Interval.MONTHLY) )
                return false;
        }
        
        return isSucc;
    }
    */
    
    private static Float getFloatFromCursor(Cursor cursor, String column) {
        return cursor.isNull(cursor.getColumnIndex(column)) ? null : cursor
                .getFloat(cursor.getColumnIndex(column));
    }

    public static void notifyDataCollectionIsFinished(Context context,
            String[] tickers) {
        List<Stock> updatedStockList = new ArrayList<Stock>();
        for (int i = 0; i < tickers.length; i++) {
            String symbol = tickers[i];
            Stock stock = getStock(context, symbol);
            if (stock != null) {
                Cursor cursor = getLonghornDatabase(context).getStock(symbol);
                cursor.moveToFirst();
                stock.update(
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_CHANGE_PERCENTAGE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_CHANGE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_PRICE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_OPEN),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_LOW),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_HIGH),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_YESTCLOSE),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_VOLUME),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_TURNOVER),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BID1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_BIDVOL1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL1),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL2),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL3),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL4),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASK5),
                        getFloatFromCursor(cursor,
                                LonghornDatabase.KEY_STOCK_ASKVOL5),
                        cursor.getString(cursor
                                .getColumnIndex(LonghornDatabase.KEY_STOCK_UPDATE)));

                cursor.close();
                updatedStockList.add(stock);
            }
        }

        for (WeakReference<StockQuoteCollectorObserver> weakReference : DataProvider.observers
                .values()) {
            weakReference.get().refreshStockInformation(updatedStockList);
        }
    }

    public static void notifyStockDataChanged(Context context, String ticker) {
        List<Stock> updatedStockList = new ArrayList<Stock>();
        Stock stock = getStock(context, ticker);
        updatedStockList.add(stock);
        for (WeakReference<StockQuoteCollectorObserver> weakReference : DataProvider.observers
                .values()) {
            weakReference.get().refreshStockInformation(updatedStockList);
        }
    }

    private static Float getFloatFromCursorByColName(Cursor cursor,
            String column) {
        int colIdx = cursor.getColumnIndex(column);
        if (cursor.isNull(colIdx))
            return null;
        Float fValue = cursor.getFloat(colIdx);
        return fValue;
    }

    public static void checkStocksAndNotify(Context context, String[] tickers) {

        for (int i = 0; i < tickers.length; i++) {
            String symbol = tickers[i];
            String chkResult = null;
            Stock stock = getStock(context, symbol);
            if (stock != null && !stock.isMarketIndex()) {
                Cursor cursor = DataProvider.getLonghornDatabase(context)
                        .getStockTimeData(symbol);
                cursor.moveToFirst();
                int length = cursor.getCount();
                TimeSeqData newArray[] = new TimeSeqData[length];
                int arrayIdx = 0;
                for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor
                        .moveToNext()) {
                    newArray[arrayIdx] = stock
                            .CreateTimeSeqData(
                                    cursor.getLong(cursor
                                            .getColumnIndex(LonghornDatabase.KEY_STOCK_TMDATA_REC_TIME)),
                                    getFloatFromCursorByColName(
                                            cursor,
                                            LonghornDatabase.KEY_STOCK_TMDATA_REC_PRICE),
                                    getFloatFromCursorByColName(
                                            cursor,
                                            LonghornDatabase.KEY_STOCK_TMDATA_REC_VOL),
                                    getFloatFromCursorByColName(
                                            cursor,
                                            LonghornDatabase.KEY_STOCK_TMDATA_REC_TURNOVER));
                    arrayIdx += 1;
                    if (arrayIdx >= length)
                        break;
                }
                stock.updateTsArrays(newArray);

                chkResult = StockAnalysis.getInstance(context)
                        .analyseByPolices(stock);
                if (null != chkResult) {
                    long currentTime = System.currentTimeMillis();
                    if (currentTime - stock.lastNotifyTime > Constants.DAY_TO_MILLSECONDS) {
                        Extensions.sendDogNotification(context, chkResult);
                        stock.lastNotifyTime = currentTime;
                    }
                }
                cursor.close();
            }
        }
    }

    private static LonghornDatabase getLonghornDatabase(Context context) {
        if (DataProvider.longhornDatabase == null) {
            initialize(context);
        }
        return DataProvider.longhornDatabase;
    }

    private static HistoryQuotesDataBase getHisQutoesDatabase(Context context) {
        if (DataProvider.hisQuotesDatabase == null) {
            initialize(context);
        }
        return DataProvider.hisQuotesDatabase;
    }
    
    private static StockInfoDatabase getStockInfoDatabase(Context context) {
        if (DataProvider.stockInfoDatabase == null) {
            initialize(context);
        }
        return DataProvider.stockInfoDatabase;
    }

    public static interface StockQuoteCollectorObserver {
        public void refreshStockInformation(List<Stock> stocks);
    }

}
